/**
 * @fileOverview 拖动
 * @author <a href="mailto:lexloo@126.com">lexloo</a>
 */
(function() {
	if (typeof $XDrag != 'undefined') {
		return;
	}

	$Namespace('com.firefly');

	/**
	 * 拖动对象
	 * 
	 * @class 拖动对象
	 * @version 1.0
	 * @author <a href="mailto:lexloo@126.com">lexloo</a>
	 * @constructor
	 * @param {HTMLElement/String}
	 *            handle 拖动元素 *
	 * @param {HTMLElement/String}
	 *            [root] 根元素，如果为空则为handle
	 * @param {Object}
	 *            [options] 参数
	 */
	com.firefly.XDrag = function(handle, root, options) {
		this.initialize(handle, root, options);
	};

	$Lang.extend(com.firefly.XDrag, $XEventSource, {
		mouseX : 0,
		mouseY : 0,
		lastMouseX : 0,
		lastMouseY : 0,
		mOffX : 0,
		mOffY : 0,
		minLeft : 0,
		maxLeft : 9999,
		minTop : 0,
		maxTop : 9999,
		elmX : 0,
		elmY : 0, 
		elmW : 0,
		elmH : 0, 

		/**
		 * 拖动代理
		 */
		dragDelegate : null,

		/**
		 * 拖动对象
		 */
		dragObject : null,

		/**
		 * 是否正在拖动
		 */
		isDragging : false,
		/**
		 * @constructor
		 */
		initialize : function(handle, root, options) {
			$XDrag.superclass.initialize.call(this);

			this.dragDelegate = $(handle);
			this.dragObject = $(root) || this.dragDelegate;

			if (options) {
				this.minLeft = options.minLeft || 0;
				this.maxLeft = options.maxLeft || 9999;
				this.minTop = options.minTop || 0;
				this.maxTop = options.maxTop || 9999;
			}

			this.initEvents();
		},
		/**
		 * 给容器初始化事件
		 * 
		 * @param {Object}
		 *            container 容器
		 */
		initEvents : function() {
			$XEvent.addListener(document, 'mousedown', this.mouseDown.bindAsEventListener(this));
			$XEvent.addListener(document, 'mousemove', this.mouseMove.bindAsEventListener(this));
			$XEvent.addListener(document, 'mouseup', this.mouseUp.bindAsEventListener(this));
		},

		mouseDown : function(evt) {
			this.isDragging = false;

			if ($XEvent.isConsumed(evt)) {
				return;
			}

			var el = $XEvent.getSource(evt);
			while (el) {
				if (this.dragDelegate == el) {
					this.isDragging = true;
					break;
				}

				el = el.parentNode;
			}

			if (!this.isDragging) {
				return;
			}

			$XEvent.consume(evt);

			this.dragDelegate.style.cursor = 'MOVE';
			/* 保留当前鼠标位置 */
			this.lastMouseX = $XEvent.pageX(evt);
			this.lastMouseY = $XEvent.pageY(evt);

			this.startDrag();
		},

		mouseMove : function(evt) {
			if ((!this.isDragging) || ($XEvent.isConsumed(evt))) {
				return;
			}

			$XEvent.consume(evt);

			with (this) {
				/* 保留当前鼠标位置 */
				mouseX = $XEvent.pageX(evt);
				mouseY = $XEvent.pageY(evt);

				/* 计算相对位置 */
				var diffX = mouseX - lastMouseX + mOffX;
				var diffY = mouseY - lastMouseY + mOffY;

				mOffX = mOffY = 0;

				/* 更新鼠标最后位置 */
				lastMouseX = mouseX;
				lastMouseY = mouseY;

				var dX = diffX, dY = diffY;
				if (elmX + dX < minLeft)
					mOffX = (dX - (diffX = minLeft - elmX));
				else if (elmX + elmW + dX > maxLeft)
					mOffX = (dX - (diffX = maxLeft - elmX - elmW));

				if (elmY + dY < minTop)
					mOffY = (dY - (diffY = minTop - elmY));
				else if (elmY + elmH + dY > maxTop)
					mOffY = (dY - (diffY = maxTop - elmY - elmH));

				elmX += diffX;
				elmY += diffY;

				with (dragObject.style) {
					left = elmX + 'px';
					top = elmY + 'px';
				}
			}

			this.fireEvent(new $XEventObject('move'));
		},

		mouseUp : function(evt) {
			if ((!this.isDragging) || ($XEvent.isConsumed(evt))) {
				return;
			}

			$XEvent.consume(evt);

			this.isDragging = false;

			this.dragDelegate.style.cursor = 'DEFAULT';
			this.mOffX = 0;
			this.mOffY = 0;

			this.fireEvent(new $XEventObject('move_end'));
		},

		/**
		 * 选择元素
		 * 
		 * @param elem
		 *            {DOMElement} 拖动元素
		 */
		startDrag : function() {
			var elem = this.dragObject;

			/* 显示拖动范围 */
			this.elmX = parseInt(elem.style.left);
			this.elmX = isNaN(this.elmX) ? 0 : this.elmX;

			this.elmY = parseInt(elem.style.top);
			this.elmY = isNaN(this.elmY) ? 0 : this.elmY;

			this.elmW = elem.offsetWidth;
			this.elmH = elem.offsetHeight;
		}
	});

	/**
	 * 释放对象
	 */
	com.firefly.XDrag.prototype.dispose = function() {
	};

	/**
	 * com.firefly.XDrag的快捷访问
	 */
	$XDrag = com.firefly.XDrag;
})();